package com.ecoolex.union.pay.retailer.ws;

import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.exception.BizException;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.union.pay.retailer.core.manager.UnionPayCouponCurrencyCodeManager;
import com.ecoolex.union.pay.retailer.core.manager.UnionPayCouponManager;
import com.ecoolex.union.pay.retailer.core.manager.UnionPayPopularCurrencyCodeManager;
import com.ecoolex.union.pay.retailer.core.util.UnionPayCouponSecureService;
import com.ecoolex.union.pay.retailer.core.util.unionpay.LogUtil;
import com.ecoolex.union.pay.retailer.entity.UnionPayCoupon;
import com.ecoolex.union.pay.retailer.enums.UnionPayCouponOperateType;
import com.ecoolex.union.pay.retailer.enums.UnionPayCouponStatus;
import com.ecoolex.union.pay.retailer.pojo.ManulReceiveUnionPayCouponDTO;
import com.ecoolex.union.pay.retailer.pojo.ReceiveUnionPayCouponDTO;
import com.ecoolex.union.pay.retailer.pojo.UnionPayCouponOperateRequest;
import com.ecoolex.union.pay.retailer.pojo.UnionPayCouponOperateResponse;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

@Service
public class UnionPayCouponServiceImpl implements UnionPayCouponService {

    @Autowired
    UnionPayCouponManager unionPayCouponManager;

    @Autowired
    UnionPayCouponSecureService unionPayCouponSecureService;

    @Override
    public Pagination<UnionPayCoupon> getCouponByUserId(Integer userId, Page page) {
        return unionPayCouponManager.getCouponsByUserId(userId, page);
    }

    @Override
    public void receiveUnionPayCoupon(ReceiveUnionPayCouponDTO coupon, Integer userId, String userName) {
        String json = coupon.getCouponList();
        if(Check.isNullOrEmpty(json)) {
            return;
        }
        List<UnionPayCoupon> oldUnionPayCouponList = unionPayCouponManager.getCouponsByUserId(userId);

        List<UnionPayCoupon> unionPayCouponList = wrapUnionPayCoupon(coupon,userId,userName);
        Map<String,UnionPayCoupon> couponHashMap = new HashMap<>();
        unionPayCouponList.forEach(item ->{
            couponHashMap.put(item.getCouponCode(),item);
        });
        //处理已经已经存在或作废失效的优惠券
        oldUnionPayCouponList.forEach(unionPayCoupon ->{
            try{
                String couponCode = unionPayCoupon.getCouponCode();
                if(couponHashMap.containsKey(couponCode)){
                    //已经存在的跳过
                }else { //作废失效的优惠券
                    unionPayCouponManager.invalid(unionPayCoupon);
                }
                couponHashMap.remove(couponCode);
            }catch (Exception ignore){
                LogUtil.writeErrorLog("保存优惠券异常",ignore);
            }
        });
        //处理新增的优惠券
        couponHashMap.values().forEach(item ->{
            try{
                unionPayCouponManager.receiveUnionPayCoupon(item);
            }catch (Exception ignore){
                LogUtil.writeErrorLog("保存优惠券异常",ignore);
            }
        });


    }

    /**
     * 封装银联优惠券
     * @param coupon
     * @param userId
     * @param userName
     * @return
     */
    private List<UnionPayCoupon> wrapUnionPayCoupon(ReceiveUnionPayCouponDTO coupon,Integer userId,String userName){
        String json = coupon.getCouponList();
        if(Check.isNullOrEmpty(json)) {
            return Collections.emptyList();
        }

        JsonArray couponList  = new JsonParser().parse(json).getAsJsonArray();
        List<UnionPayCoupon> unionPayCouponList = new ArrayList<>(couponList.size());
        couponList.forEach(item ->{
            try{
                JsonObject  _coupon = item.getAsJsonObject();
                String couponId = _coupon.get("couponId").getAsString();
                String couponName = _coupon.get("couponName").getAsString();

                UnionPayCoupon unionPayCoupon = new UnionPayCoupon();
                unionPayCoupon.setCouponCode(couponId);
                unionPayCoupon.setCouponName(couponName);
                unionPayCoupon.setStatus(UnionPayCouponStatus.UNUSED.real());
                unionPayCoupon.setReducePrice(BigDecimal.ZERO);
                unionPayCoupon.setStartEffectiveTime(Date.from(Instant.now().minus(1,ChronoUnit.DAYS)));
                unionPayCoupon.setEndEffectiveTime(Date.from(Instant.now().plus(1,ChronoUnit.DAYS)));
                unionPayCoupon.setCanUsed(true);
                unionPayCoupon.setUserId(userId);
                unionPayCoupon.setCreateUser(userName);
                unionPayCoupon.setCreateTime(Date.from(Instant.now()));
                unionPayCoupon.setUpdateUser(userName);
                unionPayCoupon.setUpdateTime(Date.from(Instant.now()));
                unionPayCoupon.setDeleted(UnionPayCoupon.NOT_DELETED);
                unionPayCouponList.add(unionPayCoupon);
            }catch (Exception ignore){
                LogUtil.writeErrorLog("封装优惠券异常",ignore);
            }
        });
        return unionPayCouponList;
    }

    @Override
    public UnionPayCoupon manulReceiveUnionPayCoupon(ManulReceiveUnionPayCouponDTO coupon, Integer userId, String userName) {
        List<UnionPayCoupon> extised = unionPayCouponManager.checkCouponExists(coupon.getCouponCode(), userId);
        if(Check.notEmpty(extised)){
            throw new BizException(ResultCode.BIZ.build(12), "优惠券无法重复添加");
        }
        UnionPayCouponOperateRequest entity = new UnionPayCouponOperateRequest();
        entity.setProcType(UnionPayCouponOperateType.COUPON_QUERY.real());
        entity.setCouponId(coupon.getCouponCode());
        entity.setTransCurr(UnionPayCouponCurrencyCodeManager.translateCurrencyCode(coupon.getCurrencyType()));
        //保留两位小数
        entity.setTransAmt(coupon.getTotalPrice().setScale(2, RoundingMode.HALF_UP).toPlainString());
        Optional<UnionPayCouponOperateResponse> responseOptional = unionPayCouponSecureService.callUnionPayCouponService(entity);
        if(responseOptional.isPresent()){
            UnionPayCouponOperateResponse response = responseOptional.get();
            UnionPayCoupon unionPayCoupon = new UnionPayCoupon();
            unionPayCoupon.setCouponCode(coupon.getCouponCode());
            unionPayCoupon.setCouponName("优计划优惠券");
            unionPayCoupon.setStatus(UnionPayCouponStatus.UNUSED.real());
            unionPayCoupon.setReducePrice(response.getDiscountAmt());
            unionPayCoupon.setCurrencyType(UnionPayPopularCurrencyCodeManager.translateCurrencyName(response.getTransCurr()));
            Instant now =  Instant.now();
            Instant validStartDate =now;
            if(Check.notNull(response.getValidStartDate())){
                try{
                    validStartDate = LocalDateTime.from(DateTimeFormatter.ofPattern("yyyyMMddHHmmss").parse(response.getValidStartDate()+"000000")).toInstant(ZoneOffset.ofHours(8));
                }catch (Exception e){
                    LogUtil.writeErrorLog("validStartDate",e);
                    validStartDate.minus(1, ChronoUnit.DAYS);
                }
            }
            Instant validEndDate = now;
            if(Check.notNull(response.getValidStartDate())){
                try {
                    validEndDate = LocalDateTime.from(DateTimeFormatter.ofPattern("yyyyMMddHHmmss").parse(response.getValidEndDate()+"235959")).toInstant(ZoneOffset.ofHours(8));
                }catch (Exception e){
                    LogUtil.writeErrorLog("validEndDate",e);
                    validEndDate.plus(1, ChronoUnit.DAYS);
                }
            }
            unionPayCoupon.setStartEffectiveTime(Date.from(validStartDate));
            unionPayCoupon.setEndEffectiveTime(Date.from(validEndDate));
            unionPayCoupon.setCanUsed(true);
            unionPayCoupon.setUserId(userId);
            unionPayCoupon.setCreateUser(userName);
            unionPayCoupon.setCreateTime(Date.from(Instant.now()));
            unionPayCoupon.setUpdateUser(userName);
            unionPayCoupon.setUpdateTime(Date.from(Instant.now()));
            unionPayCoupon.setDeleted(UnionPayCoupon.NOT_DELETED);
            unionPayCouponManager.receiveUnionPayCoupon(unionPayCoupon);
            return unionPayCoupon;
        }
        return null;
    }

	@Override
	public boolean canUsed(UnionPayCoupon source, BigDecimal realPrice, String currencyType, Integer userId) {
		Optional<UnionPayCouponOperateResponse> responseOptional = canUsed(source.getCouponId(), realPrice,
				currencyType, userId);
		boolean canUsed = responseOptional.isPresent();
		if (canUsed) {
			UnionPayCouponOperateResponse unionPayCouponOperateResponse = responseOptional.get();
			BigDecimal reducePrice = Optional.ofNullable(unionPayCouponOperateResponse.getDiscountAmt())
					.orElse(BigDecimal.ZERO);
			source.setReducePrice(reducePrice);
		}
		return canUsed;
	}

	@Override
	public Optional<UnionPayCouponOperateResponse> canUsed(Integer couponId, BigDecimal realPrice, String currencyType,
			Integer userId) {
		try {
			if (Objects.nonNull(realPrice) && BigDecimal.ZERO.compareTo(realPrice) < 0) {
				UnionPayCoupon unionPayCoupon = unionPayCouponManager.getCouponByUserId(userId, couponId,
						UnionPayCouponStatus.UNUSED);
				if (Check.notNull(unionPayCoupon)) {
					UnionPayCouponOperateRequest entity = new UnionPayCouponOperateRequest();
					entity.setProcType(UnionPayCouponOperateType.COUPON_QUERY.real());
					entity.setCouponId(unionPayCoupon.getCouponCode());
					// 保留两位小数
					entity.setTransAmt(realPrice.setScale(2, RoundingMode.HALF_UP).toPlainString());
					entity.setTransCurr(UnionPayCouponCurrencyCodeManager.translateCurrencyCode(currencyType));
					Optional<UnionPayCouponOperateResponse> responseOptional = unionPayCouponSecureService
							.callUnionPayCouponService(entity);
					return responseOptional;
				}
			}
		}
		catch (Exception ignore) {
			LogUtil.writeErrorLog("", ignore);
		}
		return Optional.empty();
	}

}
